#region Copyright Vanderlande Industries B.V. 2009-2012
//
// Copyright (c) 2009-2012 Vanderlande Industries.
// All rights reserved.
//
// @file:     FscUtility.cs
// @version:  %version: 39 %
// %date_created: dinsdag 8 mei 2012 10:11:38 %
//
// The copyright to the computer program(s) herein is the property of
// Vanderlande Industries. The program(s) may be used and/or copied
// only with the written permission of the owner or in accordance with
// the terms and conditions stipulated in the contract under which the
// program(s) have been supplied.
//
#endregion

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using System.Windows.Forms;
//using VI.Bfw.Logging;
using VI.Fsc.OperatorGui.WebReferences.Opc;

namespace VI.Fsc.OperatorGui.Models.Application.Util
{
    public enum BrowseElementType
    {
        RSTATE,
        RSDETAILS,
        AREA,
        ZONE,
        SECTION,
        ITEM,
        OTHER
    }

    /// <summary>
    /// This class is a collection of different utilities.
    /// </summary>
    /// <remarks>This class could be merged with <see cref="Utility.cs"/> .</remarks>
    public static class CFscUtility
    {
        // Depending on the loaded dll-files the application will be identified as Operator-GUI or as Maintenance-GUI.
        private const string OPERATOR_GUI = "OperatorGUI";
        private const string MAINTENANCE_GUI = "MaintenanceGUI";

        public static double Log2(double n)
        {
            // log(n)/log(2) is log2.
            return Math.Log(n) / Math.Log(2);
        }

        public static List<string> GetProblemSolutionKeys(string binaryKey, string markCode)
        {
            List<string> allKeys = new List<string>();
            string errorCode = Convert.ToString(Int32.Parse(binaryKey), 2);
           
            // Go through all the bits of the binary representation, starting by the 
            // rightmost (less significant bit), but looping with an increasing counter.
            for (int i = 0; i < errorCode.Length; i++)
            {
                // If the bit we are checking is high, add the corresponding error.
                if (errorCode[errorCode.Length - 1 - i] == '1')
                {
                    // Get the appropriate key for this number.
                    int ErrorValue = Convert.ToInt32(Math.Pow(2, i));

                    if (ErrorValue <= CFscStrings.MAX_ID_FOR_MARKCODE_GENERAL)
                    {
                        allKeys.Add(CFscStrings.GENERAL_ERROR_PREFIX + "_" + ErrorValue);
                    }
                    else if (ErrorValue >= CFscStrings.MIN_ID_FOR_MARKCODE_MODE)
                    {
                        allKeys.Add(CFscStrings.MODE_STRING_WITHOUT_SLASH + "_" + ErrorValue);
                    }
                    else
                    {
                        allKeys.Add(markCode + "_" + ErrorValue);
                    }
                }
            }
            return allKeys;
        }

        public static string GetFullProblemKey(string parcialProblemKey)
        {
            return CFscStrings.PROBLEM_KEY.Replace("%PROBLEM_KEY%", parcialProblemKey);
        }

        public static string GetFullSolutionKey(string parcialSolutionKey)
        {
            return CFscStrings.SOLUTION_KEY.Replace("%SOLUTION_KEY%", parcialSolutionKey);
        }

        /// <summary>
        /// Method to browse a branch and return all child branches or elements.
        /// </summary>
        /// <param name="itemName"></param>
        /// <param name="browseType">The type of browsing: branch or all</param>
        /// <returns></returns>
        public static BrowseElement[] ExecuteBrowseCall(string itemName, browseFilter browseType, XmlQualifiedName[] propertyNames)
        {
            // We only want to get the value and the timestamp properties.
            string continuationPoint = "";
            bool moreElements = false;
            bool returnPropertiesValues = true; // ((propertyNames != null) && (propertyNames.Length > 0));
            BrowseElement[] returnedElements = new BrowseElement[] { };
            OPCError[] errors = new OPCError[] { };

            try
            {
                COPCServerConnectionService.Instance.OPCServer.Browse(
                    propertyNames, /* the name of the properties to be retrieved. */
                    null, /* the locale ID. */
                    null, /* the client request handler. */
                    null, /* the item path. */
                    itemName, /* the item name. */
                    ref continuationPoint, /* the continuation point. Not used in our case. */
                    0, /* maximum numbers of elements to be returned. Setting it to 0 will return all elements. */
                    browseType, /* the type of filter to use: item, branch, all */
                    null, /* element name filter. */
                    null, /* vendor filter. */
                    false, /* flag to return (or not) all properties. */
                    returnPropertiesValues, /* flag to return (or not) the values of the properties. */
                    true, /* flag to return (or not) the error text. */
                    out returnedElements, /* the returned elements. */
                    out errors, /* the returned errors, if any. */
                    out moreElements);
            }
            catch (System.Net.WebException webException)
            {
                //Logger.Error(MethodBase.GetCurrentMethod(), webException.Message);
                COPCServerConnectionService.Instance.IsOnline = false;
                throw webException;
            }

            return returnedElements;
        }


        //New
        public static ItemValue ReadItem(string itemName)
        {
            ItemValue itemValue = null;

            if (!String.IsNullOrEmpty(itemName))
            {
                OPCError[] errors = new OPCError[] { };
                RequestOptions options = new RequestOptions();
                ReadRequestItem item = new ReadRequestItem();
                ReadRequestItemList requestItemList = new ReadRequestItemList();
                ReplyItemList replyItemList = null;

                item.ItemName = itemName;

                requestItemList.ItemPath = "";
                requestItemList.Items = new ReadRequestItem[1];
                requestItemList.Items[0] = item;

                try
                {
                    COPCServerConnectionService.Instance.OPCServer.Read(options, requestItemList, out replyItemList, out errors);

                    if (errors.Length == 0)
                    {
                        itemValue = replyItemList.Items[0];
                    }
                }
                catch (System.Net.WebException webException)
                {
                    //Logger.Error(MethodBase.GetCurrentMethod(), webException.Message);
                    COPCServerConnectionService.Instance.IsOnline = false;
                }
                catch (Exception e)
                {
                    MessageBox.Show(MethodBase.GetCurrentMethod().ToString(), e.Message);
                }
            }
            else
            {
            }

            return itemValue;
        }

        public static void SetItem(string itemName, object value)
        {
            ItemValue itemValue = new ItemValue();
            itemValue.ItemName = itemName;
            itemValue.Value = value;

            SendItemValues(itemValue);
        }

        public static void SetItems(Dictionary<string, object> itemNameValue)
        {
            if (itemNameValue != null)
            {
                List<ItemValue> itemValues = new List<ItemValue>();
                foreach (KeyValuePair<string, object> item in itemNameValue)
                {
                    ItemValue itemValue = new ItemValue();
                    itemValue.ItemName = item.Key;
                    itemValue.Value = item.Value;

                    itemValues.Add(itemValue);
                }

                SendItemValues(itemValues.ToArray());
            }
            else
            {
                //Logger.Warn(MethodBase.GetCurrentMethod(), "No items given, dictionary is null");
            }
        }

        /// <summary>
        /// Write as list of neu values to the OPC tree
        /// </summary>
        /// <param name="itemValues">list of items</param>
        private static void SendItemValues(ItemValue[] itemValues)
        {
            WriteRequestItemList requestItemList = new WriteRequestItemList();
            requestItemList.ItemPath = "";
            requestItemList.Items = itemValues;

            WriteToServer(requestItemList);
        }
        
        /// <summary>
        /// Write the value of one item to the OPC tree
        /// </summary>
        /// <param name="itemValue">item</param>
        private static void SendItemValues(ItemValue itemValue)
        {
            WriteRequestItemList requestItemList = new WriteRequestItemList();
            requestItemList.ItemPath = "";
            requestItemList.Items = new ItemValue[1];
            requestItemList.Items[0] = itemValue;

            WriteToServer(requestItemList);
        }

        /// <summary>
        /// Send the new Values to the OPC server
        /// </summary>
        /// <param name="requestItemList">list of items and values</param>
        private static void WriteToServer(WriteRequestItemList requestItemList)
        {
            RequestOptions options = new RequestOptions();
            try
            {
                COPCServerConnectionService.Instance.OPCServer.WriteAsync(options, requestItemList, false);
            }
            catch (System.Net.WebException webException)
            {
                //Logger.Error(MethodBase.GetCurrentMethod(), webException.Message);
                COPCServerConnectionService.Instance.IsOnline = false;
            }
            catch (Exception e)
            {
                throw new CFscException(MethodBase.GetCurrentMethod(), e.Message, "WriteToServerError");
            }
        }

        /// <summary>
        /// Creates a new subscribe request item, with some default values and
        /// with the provided item name.
        /// </summary>
        /// <param name="itemName">The name of the item to be created.</param>
        /// <returns></returns>
        public static SubscribeRequestItem CreateNewSubscribeRequestItem(string itemName)
        {
            SubscribeRequestItem item = new SubscribeRequestItem();

            item.Deadband = 0;
            item.DeadbandSpecified = true;

            item.EnableBuffering = false;
            item.EnableBufferingSpecified = true;

            item.RequestedSamplingRateSpecified = false;
            item.ReqType = null;

            item.ClientItemHandle = Guid.NewGuid().ToString();

            item.ItemName = itemName;

            return item;
        }

        public static bool IsMaintenanceGuiRunning()
        {
            //return VI.Bfw.Common.EnvironmentInformation.BfwConfiguration.Modules.Contains("VI.Fsc.MaintenanceGui.dll");
            return true;
        }

        public static bool IsOperatorGuiRunning()
        {
            //return VI.Bfw.Common.EnvironmentInformation.BfwConfiguration.Modules.Contains("VI.Fsc.OperatorGui.dll");
            return true;
        }

        /// <summary>
        /// Get the name of the application (OperatorGUI or MaintenanceGUI).
        /// </summary>
        /// <returns>MaintenanceGUI if its dll-file is in the list of modules, OperatorGUI otherwise</returns>
        public static string GetApplicationName()
        {
            string applicationName = string.Empty;

            if (IsMaintenanceGuiRunning())
            {
                applicationName = CFscUtility.MAINTENANCE_GUI;
            }
            else if (IsOperatorGuiRunning()) 
            {
                applicationName = CFscUtility.OPERATOR_GUI;
            }

            return applicationName;
        }
    }
}
